#include <new>

#include "../../tdp2/tdp2_math.hpp"
#include "../../tdp2/tdp2_husk.hpp"
#include "../../tdp2/tdp2_maincontext.hpp"
#include "../../tdp2/tdp2_vfs.hpp"
#include "../../tdp2/tdp2_glrenderdevice.hpp"

using namespace TDP;
using namespace TDP::Math;

extern "C"
{
#include "../renderer/tr_local.h"
}
#include "tr_r2.h"

// Clear out Win32 aliases
#ifdef DeleteFile
#  undef DeleteFile
#endif

#ifdef CreateDirectory
#  undef CreateDirectory
#endif

using namespace TDP;

class r2GLInitializer : public Rendering::IGLInitializer
{
public:
	void *GetProcAddress(const char *str) const
	{
		void *func = GLimp_GetProcAddress(str);
		return func;
	}
};

r2GLInitializer											r_glinit;
FVec4													r_tintColor;
TDP::Containers::Husk<TDP::MainContext>					r_mctx;
TDP::Containers::Husk<TDP::OS::OSFileSystem>			r_osfs;
TDP::Containers::Husk<TDP::Rendering::GLRenderDevice>	r_gldevice;


void		R2_InitTBR()
{
	const char *blame;
	const RDX::ObjectManagement::Allocator &alloc = TDP::Memory::DefaultAllocator();

	TDP_HNEW(&r_osfs, TDP::OS::OSFileSystem, (NULL, RDX_STATIC_STRING("data"), alloc));
	TDP_HNEW(&r_gldevice, Rendering::GLRenderDevice, (alloc, &r_glinit, &blame));
	if(!r_gldevice->StartedOK())
		Com_Error(ERR_DROP, "Couldn't start GL rendering device: %s blamed");
	TDP_HNEW(&r_mctx, MainContext, (NULL, NULL, TDP::Memory::DefaultAllocator(), r_osfs, r_gldevice));
}

void		R2_LoadWorldMap( const char *mapname )
{

}

void		R2_ClearScene( void )
{
}




void		R2_ShutdownTBR()
{
	r_mctx.Destroy();
	r_osfs.Destroy();
	r_gldevice.Destroy();
}

extern cvar_t *r_gamma;

void DefaultState()
{
	qglClearDepth( 1.0f );

	qglCullFace(GL_FRONT);

	qglColor4f (1,1,1,1);

	qglShadeModel( GL_SMOOTH );
	qglDepthFunc( GL_LEQUAL );

	// the vertex array is always enabled, but the color and texture
	// arrays are enabled and disabled around the compiled vertex array call
	qglEnableClientState (GL_VERTEX_ARRAY);

	//
	// make sure our GL state vector is set correctly
	//
	glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;

	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
	qglDepthMask( GL_TRUE );
	qglDisable( GL_DEPTH_TEST );
	qglDisable( GL_SCISSOR_TEST );
	qglEnable( GL_CULL_FACE );
	qglDisable( GL_BLEND );
}

void R2_RenderScene(const refdef_t *fd)
{
	/*
	terMat3x3 m;
	terQuat q;
	terCamera camera;

	DefaultState();

	qglViewport( fd->x, glConfig.vidHeight - (fd->y + fd->height), fd->width, fd->height );
	qglClear( GL_DEPTH_BUFFER_BIT );

	if(!r_tdp_renderer)
		return;

	// Orient camera
	camera.SetPosition(terVec3(fd->vieworg));
	camera.SetViewport(fd->x, fd->y, fd->width, fd->height);

	m[0] = terVec3(fd->viewaxis[0]);	// Forward
	m[1] = terVec3(fd->viewaxis[1]);	// Left
	m[2] = terVec3(fd->viewaxis[2]);	// Up

	q = m.ToQuat();
	q[3] = -q[3];
	terRotation viewRotation(q);


	camera.SetRotation(viewRotation % terRotation(terQuat(-0.5, 0.5, 0.5, -0.5)));

	camera.SetHFOV(terAngleDegrees(fd->fov_x));
	camera.SetVFOV(terAngleDegrees(fd->fov_y));


	if(!(fd->rdflags & RDF_NOWORLDMODEL))
	{
		// Need to draw the world model
		if(!r_tdp_bspVisibility || !r_tdp_bspMapModel)
			return;

		if(!r_worldModelPresent)
		{
			terBRFastLight ambientLight;

			r_worldModelPresent = true;
			r_tdp_bspMapModel->LinkToScene(r_tdp_scene);
			r_tdp_scene->AddObject(r_tdp_bspMapModel);

			ambientLight.mapAsset = r_tdp_mapAsset;
			ambientLight.lightClass = terBRLightClassBSPAmbient_k;
			r_tdp_scene->AddFastLight(&ambientLight);

			r_tdp_scene->AddMapLights(r_tdp_mapAsset);
		}

		if(r_tdp_bspVisibility)
			r_tdp_bspVisibility->AcquireVisibility(&camera);
	}
	else
	{
		if(r_worldModelPresent)
			ri.Error(ERR_DROP, "RenderScene with RDF_NOWORLDMODEL called without ClearScene first");
	}

	// New assets in the pipe, need to wait for them
	if(r_tdp_assetManager->NumPendingAssets())
		R2_WaitForLoader();

	r_tdp_scene->Draw(&camera);
	r_tdp_renderer->DrawPending();
	*/
}


void		R2_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b )
{
}

void		R2_AddModelToScene( const refEntity_t *ent )
{
}

void		R2_AddRefEntityToScene( const refEntity_t *ent )
{
	switch ( ent->reType )
	{
	case RT_PORTALSURFACE:
		break;		// don't draw anything
	case RT_SPRITE:
	case RT_BEAM:
	case RT_LIGHTNING:
	case RT_RAIL_CORE:
	case RT_RAIL_RINGS:
		break;

	case RT_MODEL:

		break;
	default:
		ri.Error( ERR_DROP, "R2_AddRefEntityToScene: Bad reType" );
	}
}


void		R2_StretchPic ( float x, float y, float w, float h, 
					  float s1, float t1, float s2, float t2, qhandle_t hShader )
{
	if(!hShader)
		return;

	x /= (float)glConfig.vidWidth;
	y /= (float)glConfig.vidHeight;
	w /= (float)glConfig.vidWidth;
	h /= (float)glConfig.vidHeight;

	qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
	qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
}

void		R2_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty)
{
	x /= (float)glConfig.vidWidth;
	y /= (float)glConfig.vidHeight;
	w /= (float)glConfig.vidWidth;
	h /= (float)glConfig.vidHeight;

	qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
	qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
}


void		R2_SetColor( const float *rgba )
{
	if(!rgba)
		r_tintColor = FVec4(1, 1, 1, 1);
	else
		r_tintColor = FVec4(rgba);
}


void		R2_BeginFrame( stereoFrame_t stereoFrame )
{
	r_mctx->PumpStreaming();
	if ( r_gamma->modified ) {
		r_gamma->modified = qfalse;

		R_SetColorMappings();
	}
}

void R2_EndFrame( int *frontEndMsec, int *backEndMsec )
{
	qglFinish();
	GLimp_EndFrame();
}
